
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 200002;
inline int read() {
  register int x = 0;
  register char c = getchar();
  for (; !(c >= '0' && c <= '9'); c = getchar())
    ;
  for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + c - '0';
  return x;
}
int n, m;
vector<int> v[maxn];  //存边
vector<int> son[maxn];
// son[i]:若i号奶牛是其所在节点的（那棵树的）根节点，
//那么存储所在节点的（那棵树的）所有节点
queue<int> q;
int fa[maxn];  // fa[i]:i号奶牛所在节点的（那棵树的）根节点
int Vis[maxn], ans[maxn];
void hb(int x, int y) {
  x = fa[x], y = fa[y];               //对根节点进行操作
  if (son[x].size() < son[y].size())  //启发式合并核心代码
    x ^= y, y ^= x, x ^= y;
  for (register int i = 0; i < v[y].size(); i++) v[x].pb(v[y][i]);  //合并
  for (register int i = 0; i < son[y].size(); i++)
    fa[son[y][i]] = x, son[x].pb(son[y][i]);  //合并
  if (v[x].size() > 1)
    //如果仰慕的奶牛超过一头，需要合并，入队列
    q.push(x);
}

int main() {
  register int x, y, t, ru;
  n = read(), m = read();
  for (register int i = 1; i <= m; i++) x = read(), y = read(), v[x].pb(y);
  for (register int i = 1; i <= n; i++) {
    fa[i] = i;  //一开始每个奶牛所在节点的根节点都是它自己
    if (v[i].size() > 1)
      //如果有超过一头奶牛仰慕当前奶牛，那么需要合并，加入队列
      q.push(i);
    son[i].pb(i);
    //一开始每个奶牛都是所在节点的根节点节点，且节点中必定有这头奶牛（废话）
  }
  while (!q.empty()) {
    t = q.front(), q.pop();
    while (v[t].size() > 1) {
      ru = v[t][1], x = v[t][0], v[t].erase(v[t].begin());
      if (fa[ru] != fa[x])
        //如果不是同一节点中的奶牛再合并，防止计算重复
        hb(ru, x);
    }
  }
  register int col = 0;
  for (register int i = 1; i <= n; i++) {
    if (Vis[fa[i]] == 0) Vis[fa[i]] = ++col;
    cout << Vis[fa[i]] << endl;
  }
  return 0;
}
